package main

import (
	"./daemonlibrary"
	"./tools"
	"encoding/json"
	"fmt"
	"github.com/zouyx/agollo"
	"net/http"
	"strings"
	"time"
)

var shellHelper tools.ShellHelper
var netHelper tools.NetHelper
var logHelper tools.LogHelper

var configMap map[string]interface{}
var arrServerConfig []*daemonlibrary.ServerModel
var localServer *daemonlibrary.ServerModel

func main() {
	//region 读取apollo配置信息&初始化日志handler
	configMap = make(map[string]interface{}, 10)
	err := agollo.Start()
	if err != nil {
		logHelper.LogError(fmt.Sprintf("启动apollo失败"), err)
		return
	} else {
		fmt.Println("apollo start success")
		fmt.Println(agollo.GetCurrentApolloConfig())
	}
	configMap["CheckServerConfig"] = agollo.GetStringValue("CheckServerConfig", "")
	configMap["CheckCommandTemplate"] = agollo.GetStringValue("CheckCommandTemplate", "ps -ef|grep %s")
	configMap["CheckExcludeString"] = agollo.GetStringValue("CheckExcludeString", "grep")
	configMap["LocalIpPrefix"] = agollo.GetStringValue("LocalIpPrefix", "192.168.0.")
	configMap["LogPath"] = agollo.GetStringValue("LogPath", "daemon-%s.log")
	//初始化日志对象
	logHelper = tools.NewLogHelper(configMap["LogPath"].(string), true, "守护进程服务")
	if configMap["serverConfig"] == "" {
		logHelper.LogInfo("未取到待监控的服务器及进程配置信息，中止......")
		return
	}
	//endregion

	//region 监听8100端口，用于校验当前服务存活状态
	go func() {
		mux := http.NewServeMux()
		mux.HandleFunc("/", handlerPort)
		http.ListenAndServe(":8100", mux)
	}()
	//endregion

	//region 初始化apollo配置&监听apollo配置变动信息
	initServerConfig()
	go func() {
		apolloEventHandler()
	}()
	//endregion

	for {
		//region 遍历服务器配置列表，找出当前服务器并处理
		var aliveStatus bool //进程存活状态
		fmt.Println("start server:" + localServer.ServerIp)
		if len(localServer.ProcessList) == 0 {
			logHelper.LogInfo(fmt.Sprintf("当前服务器没有配置待监听的进程信息：%s", localServer.ServerIp))
			return
		}
		for i, model := range localServer.ProcessList {
			//region ps命令遍历每一个待监听的进程
			aliveStatus = false
			logHelper.LogInfo(fmt.Sprintf("start check num：%d，Title：%s,CheckName：%s", i+1, model.Title, model.CheckName))
			commandstr := fmt.Sprintf(configMap["CheckCommandTemplate"].(string), model.CheckName)
			logHelper.LogInfo("execute shell:" + commandstr)
			result, err := shellHelper.ExecCommandWithOutput(commandstr)
			arr := strings.Split(result, " ")
			if err != nil {
				logHelper.LogError(fmt.Sprintf("执行命令异常：%s", commandstr), err)
				continue
			}
			//endregion

			//region 判断进程存活状态
			if arr != nil && len(arr) > 0 {
				for _, str := range arr {
					if !strings.Contains(str, configMap["CheckExcludeString"].(string)) && strings.Contains(str, model.CheckName) {
						//找到匹配的进程，判定存活
						aliveStatus = true
						break
					}
				}
			} else {
				logHelper.LogInfo(fmt.Sprintf("判断进程存活状态返回值为空：%s", commandstr))
				continue
			}
			logHelper.LogInfo(fmt.Sprintf("进程状态判定结果：%v", aliveStatus))
			//endregion

			if !aliveStatus {
				//region 进程已死，执行apollo中配置的启动进程命令
				result, err := shellHelper.ExecCommandWithOutput(model.StartCmd)
				if err != nil {
					//启动异常
					logHelper.LogError(fmt.Sprintf("启动进程失败：%s", model.StartCmd), err)
				} else {
					//启动成功
					logHelper.LogInfo(fmt.Sprintf("启动进程成功：%s，返回值：%s", model.StartCmd, result))
				}
				//endregion
			}
		}
		//endregion

		logHelper.LogInfo(fmt.Sprintf("休眠10秒，配置测试：%s", configMap["LocalIpPrefix"].(string)))
		time.Sleep(10 * time.Second)

	}

}

//region 监听默认端口，用于判定守护进程服务是否存活
func handlerPort(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "ok")
}

//endregion

//region apollo配置相关处理

//region 监听配置变动事件
func apolloEventHandler() {
	objchan := agollo.ListenChangeEvent()
	for {
		if apolloevent, ok := <-objchan; ok {
			if apolloevent.Changes == nil || len(apolloevent.Changes) == 0 {
				continue
			}
			for key, val := range apolloevent.Changes {
				//更新map中的key值
				configMap[key] = val.NewValue
				logHelper.LogInfo(fmt.Sprintf("配置信息变更：key=%s，oldvalue=%v，newvalue=%v", key, val.OldValue, val.NewValue))
				if key == "CheckServerConfig" {
					//服务器进程配置变动，重新初始化本机待监听的进程列表
					initServerConfig()
				}
			}
			continue
		}
		time.Sleep(5 * time.Second)
	}
}

//endregion

//region 初始化服务器进程配置数据
func initServerConfig() {
	//region 取出本机内网IP，用于过滤待监听的进程配置信息
	localip := netHelper.GetIntranetIp(configMap["LocalIpPrefix"].(string))
	if localip == "" {
		//获取本机IP失败，终止
		logHelper.LogInfo("获取本机IP地址失败，终止操作")
		return
	}
	//endregion

	//region 取出待监听的服务器及进程列表，筛选当前运行服务器
	json.Unmarshal([]byte(configMap["CheckServerConfig"].(string)), &arrServerConfig)
	for _, serverModel := range arrServerConfig {
		if serverModel.ServerIp == localip {
			localServer = serverModel
			logHelper.LogInfo(fmt.Sprintf("更新本服务器进程配置：%s，配置信息：%v", localip, serverModel.ProcessList))
			break
		}
	}
	//endregion
}

//endregion

//endregion
